﻿#ifndef __SCENE_GRAPH_H__
#define __SCENE_GRAPH_H__

#pragma once

#include "SceneNode.h"
#include "RenderObject.h"
#include "Light.h"

namespace Nezha
{

	class RenderTarget;
	class Camera;
	class RenderQueue;
	class BasicGeometry;
	class Renderer;

	//
	class NEZHA_ENGINE_ENTRY SceneObjectCreation
	{
	public:
		virtual ~SceneObjectCreation(){}

		virtual SceneNode* create(const _string& name) = 0;
	};

	/** Scene manager base.
	*/
	class NEZHA_ENGINE_ENTRY SceneGraph
	{
	public:
		virtual ~SceneGraph();

		// must be called at initial stage.
		void initialize();

		// create an empty scene node.
		SceneNode* createSceneNode(const _string& name, SceneNode* parent);

		virtual SceneNode* findSceneNode(const _string& name) = 0;

		/**
		@REMARKS
			all its children will be destroyed.
		*/
		virtual void destroySceneNode(SceneNode* sn) = 0;

		SceneNode* create(const _string& name, SceneObjectCreation* sc);

		Camera* createCamera(const _string& name, bool perspective);

		Camera* getCamera(const _string& name);

		void destroyCamera(Camera* cam);

		Light* createLight(const _string& name);

		Light* getLight(const _string& name);

		void destroyLight(Light* lit);

		// built in objects
		BasicGeometry* createBuiltInBox(const _string& name);

		BasicGeometry* createBuiltInPlane(const _string& name, u16 xExtent, u16 yExtent);

		BasicGeometry* createBuiltInSphere(const _string& name);

		virtual void update(float dt) = 0;

		/** 
		*/
		virtual void determineVisibleObjects(RenderTarget* rt, int flag);

		virtual void determinePSC(Light* lit);

		SceneNode* getRootNode()
		{
			return mRootNode;
		}

		//static const _string& SceneObjectTypeString(SceneObjectType sot);

		void cullLightsByCamera(Camera* cam, LightVector& lights);

		void getAffectLights(LightList& lights, SceneNode* sn);

		void destroyAllObjects();

		SceneGraph();
	protected:
		virtual void _initialize() = 0;

		virtual SceneNode* createNodeImpl(const _string& name){ return NULL; }

		virtual void _insertNode(SceneNode* sn) = 0;

		void cullObjectsByCamera(RenderTarget* rt, SceneNode* sn, int flag);

		bool cullLight(Camera* cam, Light* lit);

		virtual void _destroyAllObjects() = 0;

		void destroyAllLights();

		void destroyAllCameras();

		SceneNode* mRootNode;

		typedef PMap<_string, Camera*, _NzStrLess> CameraNameMap;

		CameraNameMap mCameras;

		typedef PMap<_string, Light*, _NzStrLess> LightNameMap;

		LightNameMap mLights;

		Renderer* mRenderer;
	private:
		//SceneObjectFactory* mBulitInMeshCreator;
	};

	class NEZHA_ENGINE_ENTRY SceneGraphCreator
	{
	public:
		virtual ~SceneGraphCreator(){}

		virtual SceneGraph* create() = 0;
	};

}//end namespace Nezha

#endif //end __SCENE_GRAPH_H__